package 进阶阶段;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class demo15线程同步机制 {
    public static void main(String[] args) {
        //线程同步机制：线程同步机制是一套用于协调线程间的数据访问及活动的机制，该机制用于保障线程安全以及实现这些线程的共同目标。
            //1. 同步代码块。
            //2. 同步方法。
            //3. 锁机制。

        //同步代码块：synchronized关键字可以用于方法中的某个区块中，表示只对这个区块的资源实行互斥访问。
            //锁对象可以是任意的,但是如果这个同步代码块被多次调用,要求锁对象是唯一,同步一个个线程,只让一个线程进来搞事情,其他线程不能进来,在外面等着,等你做完事情,释放锁才能一个个进来

        //创建4个线程
//        Window window1 = new Window("窗口一");
//        window1.start();
//
//        Window window2 = new Window("窗口二");
//        window2.start();
//
//        Window window3 = new Window("窗口三");
//        window3.start();
//
//        Window window4 = new Window("窗口四");
//        window4.start();

        //创建线程任务
        Window windowOne = new Window();
        //创建三个窗口对象
        Thread thread1 = new Thread(windowOne , "第一个线程");
        Thread thread2 = new Thread(windowOne , "第二个线程");
        Thread thread3 = new Thread(windowOne , "第三个线程");

        thread1.start();
        thread2.start();
        thread3.start();

    }
}

class Window /*extends Thread*/ implements Runnable{//继承Thread，或者实现Runnable接口

    static int ticjet = 100;

    Lock lock = new ReentrantLock();//多态写法,父接口引用指向接口的实现类对象

//    public Window(String name) {
//        super(name);
//    }

    @Override
    public void run() {

        while(true){//Runnable共享资源,同一个锁对象

            lock.lock();//上锁,相当于关门,互斥锁,一个线程进来

            if(ticjet > 0){//有票 可以卖
                //出票操作
                //使用sleep模拟一下出票时间
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //获取当前线程对象的名字
                String name = Thread.currentThread().getName();
                System.out.println(name+"正在卖:" + ticjet--);
            }

            lock.unlock();//释放锁,相当于开门
        }
    }

//        System.out.println("-------------------------------------------------------");

//        while (true){

            //同步代码块：synchronized关键字可以用于方法中的某个区块中，表示只对这个区块的资源实行互斥访问。
//            synchronized (Window.class){
//
//                if (ticjet < 0){
//                    break;
//                }
//
//                //模拟真实的情况时存在买票时间，四个线程都进来睡眠，醒来后自身可能是1或者0，导致结果就是卖出了零和负数的票
//                //发生的原因：有多个线程进来操作同一个共享数据ticjet
//                //解决办法：使用线程同步机制
//                try {
//                    sleep(300);
//                } catch (InterruptedException e) {
//                    throw new RuntimeException(e);
//                }
//
//                System.out.println(getName() + "正在卖第" + ticjet-- + "张票");

//            }

//            sellTicket();
//        }
//    }

    //同步方法:使用synchronized修饰的方法,就叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外等着
        //对于非static方法,同步锁就是this
        //对于static方法,我们使用当前方法所在类的字节码对象(类名.class)。
//    public synchronized void sellTicket(){//this锁对象
//
//        if (ticjet > 0){
//
//            try {
//                sleep(300);
//            } catch (InterruptedException e) {
//                throw new RuntimeException(e);
//            }
//
//            System.out.println(getName() + "正在卖第" + ticjet-- + "张票");        }
//
//    }
}
